로딩 중이에요... 🐣
12 에러처리하기 | ✅ 저자: 이유정(박사)
FastAPI에서 에러 처리(Error Handling)는 “클라이언트가 잘못된 요청을 보냈을 때”나 “서버 내부에서 예기치 못한 일이 발생했을 때” 적절한 HTTP 상태 코드와 메시지를 돌려줘서, API 소비자(프론트엔드나 다른 서비스)가 무슨 일이 생겼는지 알 수 있도록 돕는 기능입니다.
HTTP 상태 코드(Status Code)란?
- 200번대: 성공적인 요청
- 400번대: 클라이언트 잘못(요청 자체 문제)
- 500번대: 서버 내부 문제
예:404 Not Found
: 요청한 리소스가 없음422 Unprocessable Entity
: 검증(Validation)에 실패500 Internal Server Error
: 예기치 못한 서버 오류
HTTPException
으로 간단히 에러 내기
FastAPI가 제공하는 HTTPException
클래스를 raise
하면, 지정한 상태 코드와 메시지(detail)가 그대로 클라이언트에 반환됩니다.
Django에서는 에러 처리를 프레임워크가 자동으로 해주는 경우가 많습니다. Django는 웹 페이지 중심이라서 자동 처리와 기본 HTML에러 페이지를 기본으로 제공합니다. 그러나 FastAPI는 API 중심이라서 에러 처리를 직접 지정해야 합니다.
FastAPI에서 에러를 처리하는 4가지 대표적인 방법: FastAPI에서는 에러를 처리할 때 상황에 따라 적절한 방식이 달라집니다. 아래 코드는 그에 따른 4가지 대표적인 처리 방식을 보여줍니다.
- 기본
HTTPException
사용하기
# handling_exception.py
from fastapi import FastAPI, HTTPException
app = FastAPI()
items = {
"apple": "사과입니다",
"banana": "바나나입니다",
"grape": "포도입니다"
}
@app.get("/items/{item_id}") # items의 딕셔너리 키
async def read_item(item_id: str):
if item_id not in items:
# 아이템이 없으면 404 에러를 발생시킵니다.
raise HTTPException(status_code=404, detail="Item not found")
return {"item": items[item_id]}
- 가장 기본적이고 자주 쓰는 방식
- 특정 조건에서 예외를 던지고 → FastAPI가 자동으로 JSON 에러 응답을 만들어 줌
- 예: 404 Not Found, 403 Forbidden, 401 Unauthorized 등
- 간단한 예외 처리에 적합
- 별도 설정 없이 바로 사용 가능
HTTPException
+ 커스텀 헤더
# http_exception_with_custom_headers.py
from fastapi import FastAPI, HTTPException
app = FastAPI()
items = {
"apple": "사과입니다",
"banana": "바나나입니다",
"grape": "포도입니다"
}
@app.get("/items-header/{item_id}")
async def read_item_header(item_id: str):
if item_id not in items:
# 헤더를 직접 지정해서 반환할 수 있습니다.
raise HTTPException(
status_code=404,
detail="Item not found",
headers={"X-Error": "There goes my error"},
)
return {"item": items[item_id]}
- 에러 응답에 특정 헤더를 추가해서 전달하고 싶은 경우 사용
- 예: 클라이언트에게 에러 코드나 상태를 헤더로 전달할 때 ✔ 보안, 상태, 오류 추적 등 목적의 메타정보 전달에 유용
content-length: 26
- 응답 본문의 바이트 크기입니다.
- 즉, JSON 응답의 길이가 26바이트라는 뜻이에요. 예: 응답 내용이
{"message": "hello world!"}
같은 경우, 이 문자열의 길이를 byte 단위로 계산한 값입니다.
content-type: application/json
- 응답의 데이터 형식을 알려줍니다.
- 여기서는 JSON 형식이라는 뜻이에요.
- 브라우저나 앱은 이걸 보고 JSON으로 파싱하게 됩니다.
date: Wed, 16 Jul 2025 15:16:39 GMT
- 응답이 생성된 날짜와 시간(GMT 기준)입니다.
- 클라이언트는 이걸 보고 응답 시점이나 캐시 처리에 참고할 수 있어요.
server: uvicorn
- 이 응답을 만들어낸 서버의 이름입니다.
uvicorn
은 FastAPI가 사용하는 ASGI 웹 서버입니다. 즉, “이 응답은 uvicorn 서버가 만들어서 보냈습니다” 라는 뜻이에요.
커스텀 예외 클래스 + 전용 핸들러
# custom_exception_handler.py
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
# 1) 커스텀 예외 클래스 정의
class UnicornException(Exception):
def __init__(self, name: str):
self.name = name
app = FastAPI()
# 2) 해당 예외 전용 핸들러 등록
@app.exception_handler(UnicornException)
async def unicorn_exception_handler(request: Request, exc: UnicornException):
return JSONResponse(
status_code=418,
content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."},
)
# 3) 라우트에서 예외 발생
@app.get("/unicorns/{name}")
async def read_unicorn(name: str):
if name == "yolo":
raise UnicornException(name=name)
return {"unicorn_name": name}
-
내가 정의한 특정 예외 클래스가 발생했을 때만,
→ 맞춤 응답 형식이나 메시지를 줄 수 있음 -
JSON 구조도 완전히 내 마음대로 조절 가능
✔ 특정 조건에서 전용 에러 메시지나 로직을 처리하고 싶을 때
✔ 사용자 친화적인 에러 메시지 필요할 때
기본(Starlette) 핸들러 오버라이드
# override_exception_handlers.py
from fastapi import FastAPI, HTTPException, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import PlainTextResponse
from starlette.exceptions import HTTPException as StarletteHTTPException
app = FastAPI()
# 1) Starlette의 HTTPException 핸들러 오버라이드
# # FastAPI 내부의 HTTPException도 결국 Starlette 기반이라 이 핸들러가 작동함
@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
return PlainTextResponse(str(exc.detail), status_code=exc.status_code)
# PlainTextResponse(...) → JSON 대신 텍스트 형태로 에러 메시지 응답
# 2) 요청 검증 에러(RequestValidationError) 핸들러 오버라이드
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
return PlainTextResponse(str(exc), status_code=400)
# 3) 테스트용 엔드포인트
@app.get("/items/{item_id}")
async def read_item(item_id: int):
# item_id가 3이면 418 에러 발생
if item_id == 3:
raise HTTPException(status_code=418, detail="Nope! I don't like 3.")
return {"item_id": item_id}
-
FastAPI 내부에서 기본적으로 사용하는 에러 핸들러 자체를 덮어쓰기(override)
-
모든 에러의 응답 형식을 전역적으로 통일하고 싶을 때 사용
✔ 전체 프로젝트에서 에러 메시지 구조, 응답 형태를 통일하고 싶을 때
✔ Swagger 문서용 에러 메시지를 재정의할 때
1.
from fastapi import FastAPI, HTTPException, Request
🔹 HTTPException
- HTTP 상태 코드 에러를 일으킬 때 사용하는 예외 클래스
- 예: 404 Not Found, 401 Unauthorized, 403 Forbidden 등을 발생시킬 수 있어요
raise HTTPException(status_code=404, detail="Not found")
🔹 Request
- 들어온 HTTP 요청의 전체 내용을 담고 있는 객체
- 에러 핸들러 함수에서 보통 사용돼요
@app.exception_handler(SomeException)
async def handler(request: Request, exc: SomeException):
...
2.
from fastapi.exceptions import RequestValidationError
- 요청(request)에 검증 오류(Validation Error)가 발생했을 때 자동으로 발생하는 예외 클래스
- 예를 들어, 쿼리 파라미터 타입이 잘못되었거나,
Pydantic
모델에 맞지 않는 데이터가 들어왔을 때
@app.exception_handler(RequestValidationError)
async def validation_handler(request: Request, exc: RequestValidationError):
return PlainTextResponse("입력값이 잘못됐습니다", status_code=400)
3.
from fastapi.responses import PlainTextResponse
- 응답(Response)을 일반 텍스트로 반환하는 클래스
- JSON이 아니라 그냥 문자열을 그대로 사용자에게 보여주고 싶을 때 사용
return PlainTextResponse("오류 발생", status_code=400)
4.
from starlette.exceptions import HTTPException as StarletteHTTPException
- FastAPI는 내부적으로 Starlette 프레임워크를 기반으로 작동합니다.
HTTPException
은 FastAPI에도 있지만, Starlette에도 정의되어 있어요.- 이 코드는 Starlette에서 발생하는 HTTPException을 직접 처리하고 싶을 때 사용합니다.
@app.exception_handler(StarletteHTTPException)
async def override_http_exception(request: Request, exc: StarletteHTTPException):
return PlainTextResponse(str(exc.detail), status_code=exc.status_code)
Starlette는 FastAPI의 핵심 엔진 역할을 해주는 하위 프레임워크예요.
- FastAPI는 라우팅, 유효성 검사(Pydantic), 자동 문서화(OpenAPI) 등을 편리하게 제공합니다.
- 하지만:
- 요청(Request) 객체 처리
- 응답(Response) 반환
- 예외 처리(Exception)
- 미들웨어(Middleware) : 사용자 요청이 들어오면 로그를 남기거나, 인증/보안 검사를 하거나, 응답을 변경하기도 하기도 하는 중간 계층입니다.
- 웹소켓(WebSocket) : 기존 HTTP처럼 요청-응답 한 번으로 끝나는 게 아니라, 서버와 클라이언트가 실시간으로 양방향 통신을 할 수 있게 해주는 기술입니다. 예) 채팅앱, 실시간주식/게임 데이터전송, loT 디바이스 통신
이런 낮은 수준의 HTTP 관련 기능은 모두 Starlette가 처리합니다.
@app.exception_handler(...)
→ 예외 발생 시 처리해줄 함수 등록PlainTextResponse(...)
→ 응답을 "문자 그대로 텍스트"로 돌려줌